package com.rc.mutievcharger.dto.ylevcharger.terminal;

import com.rc.evcharger.common.annotation.ByteLength;
import com.rc.evcharger.common.base.AbstractTerminalMessage;
import com.rc.evcharger.common.base.yl.BaseYlDataType;
import com.rc.evcharger.common.utils.CRC16Util;
import com.rc.evcharger.common.utils.NumberUtil;
import com.rc.mutievcharger.dto.ylevcharger.utils.YlMessageUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;

import static com.rc.evcharger.common.utils.DataUtil.SPLIT;

/**
 * 智充帧格式说明
 * Created by Sven on 2021/04/04
 * <p>
 * <p>
 *  起始标识符代表一帧数据的开始，固定为 0x68。
 *  数据域字节数，数据域长度不超过 200 字节。不加密时为原数据长度,加密时，为加密后数据长
 * 度。其值为“序列号域+加密标志+桢类型标志+消息体”字节数之和。
 *  序列号域即为数据包的发送顺序号，从 0 开始顺序增加，如是应答数据包，则与询问数据包序
 * 号保持一致，当桩与平台网络断开重新建立连接或者溢出后归 0。
 *  加密标志只针对消息体（数据单元）。0x00:不加密，0x01:3DES
 *  桢类型标志定义了上下行数据桢。
 *  桢校验域：从序列号域到数据域的 CRC 校验，校验多项式为 0x180D,低字节在前，高字节在后，
 * 计算方式见附录。
 */
public class YlTerminalMessage extends AbstractTerminalMessage {
    private static final long serialVersionUID = -3913389249597127881L;
    static Logger logger = LoggerFactory.getLogger(YlTerminalMessage.class);

    @ByteLength(length = 2)
    private String start_sign;//起始帧头：0xAA 0xF5
    @ByteLength(length = 2)
    private String length;//数据长度    本字段包含了本条报文的总共长度信息，最大长度为 FF
    @ByteLength(length = 1)
    private String info;//版本域    本字段未做严格验证使用，仅仅用于收发报文的一致性的辨识。
    @ByteLength(length = 1)
    private String msta;//序列号域
    @ByteLength(length = 2)
    private String contral;//命令代 CMD
    @ByteLength(length = 0)
    private String data;//数据域
    @ByteLength(length = 1)
    private String cs;//校验和域 桢校验域：从序列号域到数据域的 CRC 校验，校验多项式为 0x180D,低字节在前，高字节在后

    private String body;//消息主体

    public YlTerminalMessage() {
        super();
    }

    //
    public YlTerminalMessage(String rtua, String contral, BaseYlDataType dataType) {
        super.terminalId = rtua;
        this.info = "00";
        this.msta = "00";
        this.contral = contral;
        this.data = dataType.createFrame();
        this.length = dataType.getLength();//getLength方法要在createFrame方法后调用
    }


    public YlTerminalMessage(int start, int end, String[] bcdCode) throws Exception {
        int index = start;
        Field[] fields = this.getClass().getDeclaredFields();
        StringBuffer sb = null;
        for (Field field : fields) {
            ByteLength bl = field.getAnnotation(ByteLength.class);
            if (bl == null) {
                continue;
            }
            int length = bl.length();
            if (field.getName().equals("data")) {
                String str = this.length.substring(0, 2);
                length = Integer.parseInt(str, 16);
            }
            if (field.getName().equals("contral")) {//跳过  主站后面的的68帧头
                if (!this.start_sign.equals(bcdCode[index]))
                    throw new Exception();
                index++;
            }
            sb = new StringBuffer();
            for (int i = index; i < index + length; i++) {
                sb.append(bcdCode[i]).append(SPLIT);
            }
            index += length;
            try {
                field.set(this, sb.toString().trim());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 公共构造响应帧
     *
     * @param message
     * @return
     */
    public static String getResponse(YlTerminalMessage message, String responseCode, boolean hasData) {
        try {
            if (!hasData) {
                message.setData("");
            }
            message.setContral(responseCode);
            int len = 0;
            if (message.getData().length() > 0) {
                len = message.getData().split(SPLIT).length;
            }
            String hex = Integer.toHexString(len);
            if (hex.length() == 1) {
                hex = "0" + hex;
            }
            hex = hex.toUpperCase();
            String length = hex + SPLIT + "00";
            message.setLength(length);
        } catch (Exception e) {
            logger.error("公共构造响应帧message：" + message.getBody());
            logger.error("公共构造响应帧：" + e.toString());
        }
        return createFrame(message);
    }


    /**
     * 将数据变成帧格式
     *
     * @param message
     * @return
     */
    public static String createFrame(YlTerminalMessage message) {

        StringBuffer sb = new StringBuffer("");
        try {
            sb.append(YlMessageUtil.START_SIGN).append(SPLIT).append(message.getTerminalId()).append(SPLIT);
            if (message.getMsta() != null) {
                sb.append(message.getMsta()).append(SPLIT);
            } else {
                sb.append(message.getMsta()).append(SPLIT);
            }
            sb.append(YlMessageUtil.START_SIGN).append(SPLIT)
                    .append(message.getContral()).append(SPLIT).append(message.getLength()).append(SPLIT);
            if (message.getData() != null && message.getData().length() > 0) {
                sb.append(message.getData()).append(SPLIT);
            }

            String cs = CRC16Util.getCrc(CRC16Util.calcCrc16(NumberUtil.hexStr2BinArr(sb.toString().replace(" ", ""))));    //生成校验码
            if (cs.length() < 2)
                sb.append("0");
            sb.append(cs);
        } catch (Exception e) {
            logger.error("将数据变成帧格式帧message：" + message.getBody(), e);
        }
        return sb.toString();
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    public String getStart_sign() {
        return start_sign;
    }

    public void setStart_sign(String start_sign) {
        this.start_sign = start_sign;
    }

    public String getMsta() {
        return msta;
    }

    public void setMsta(String msta) {
        this.msta = msta;
    }

    public String getContral() {
        return contral;
    }

    public void setContral(String contral) {
        this.contral = contral;
    }

    public String getLength() {
        return length;
    }

    public void setLength(String length) {
        this.length = length;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getCs() {
        return cs;
    }

    public void setCs(String cs) {
        this.cs = cs;
    }

    @Override
    public String toString() {
        return "ZCMessage [start_sign=" + start_sign + ", msta=" + msta + ", contral=" + contral + ", length="
                + length + ", data=" + data + ", cs=" + cs + "]";
    }

    /**
     * @return the body
     */
    public String getBody() {
        return start_sign + " " + length + " " + msta + " " + info + " " + contral + " "
                + data + " " + cs;
    }

    /**
     * @return the 校验数据
     */
    public String getCheckBody() {
        return contral + " " + data;
    }

    /**
     * @param body the body to set
     */
    public void setBody(String body) {
        this.body = body;
    }

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("01 02 00 00 01 05");
        sb.replace(10, 11, "1");
        System.out.println(sb.toString());
    }
}
